#include "face_mood_reader.hpp"

#include <gflags/gflags.h>
#include <utils/images_capture.h>
#include <utils/object_detector.hpp>
#include <utils/socket_client.hpp>

static const char *Usage = R"(
demo_plate_matcher [OPTIONS]
    -h              Print a usage message.
    -l              List available devices.
    -v              Visit media. default yes.
    -i              Required. input file.
    -m              Required. root directory of models.
    -d              Optional. target device.
    -ip             Server IP address.
    -port           Server port.
    -min            Minimum recording interval.
)";
DEFINE_bool(h, false, "");
DEFINE_bool(l, false, "");
DEFINE_bool(v, true, "");
DEFINE_string(i, "", "");
DEFINE_string(m, "~/models", "");
DEFINE_string(d, "CPU", "");
DEFINE_string(ip, "127.0.0.1", "");
DEFINE_int32(port, 6666, "");
DEFINE_int32(min, 10, "");


int main (int argc, char* *argv) {
    gflags::ParseCommandLineNonHelpFlags(&argc, &argv, true);
    if (FLAGS_h) {
        printf("%s", Usage);
        return 0;
    }
    InferenceEngine::Core ie;
    if (FLAGS_l) {
        auto devices = ie.GetAvailableDevices();
        for (auto &name : devices)
            printf("%s\n", name.c_str());
        return 0;
    }
    if (FLAGS_i.empty()) {
        printf("No input file.\n");
        return -1;
    }
    if (FLAGS_m.empty()) {
        printf("No model directory.\n");
        return -1;
    }
    auto media = openImagesCapture(FLAGS_i, true);
    auto first = media->read();
    if (!first.data) {
        printf("Failed to read input.\n");
        return -1;
    }
    if (FLAGS_i.front() == '~')
        FLAGS_i.replace(0, 1, std::getenv("HOME"));
    if (FLAGS_m.front() == '~')
        FLAGS_m.replace(0, 1, std::getenv("HOME"));

    ObjectDetector detector(ie, FLAGS_d, FLAGS_m + "/face-detection-adas-0001.xml");
    FaceMoodReader moodReader(ie, FLAGS_d, FLAGS_m);
    SocketClient client(FLAGS_ip, FLAGS_port);
    struct Data : public SocketMessage {
        long time;
        std::vector<const char*> items;
        std::vector<char> encode () const override {
            std::vector<char> res(4096 * 2);
            int i = sprintf(res.data(), R"({"time":%ld,"items":[)", time);
            for (auto name : items)
                i += sprintf(res.data() + i, R"("%s",)", name);
            if (res[i - 1] == ',')
                i--;
            i += sprintf(res.data() + i, "]}\n");
            res.resize(i);
            return res;
        }
    };

    int lastRecording = 0;
    for (int frameId = 1; ; ++frameId) {
        auto frame = media->read();
        if (!frame.data)
            break;
        auto objects = detector.infer(frame);
        auto data = std::make_shared<Data>();
        using namespace std::chrono;
        data->time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
        for (auto &obj : objects) {
            cv::Rect rect(
                    obj.x * frame.cols,
                    obj.y * frame.rows,
                    obj.w * frame.cols,
                    obj.h * frame.rows);
            auto objFrame = frame(rect);
            auto res = moodReader.infer(objFrame);
            data->items.push_back(FaceMoodReader::MoodNames[res.index]);
        }
        if (frameId - lastRecording >= FLAGS_min && !data->items.empty()) {
            lastRecording = frameId;
            client.write(data);
        }
        if (FLAGS_v) {
            cv::imshow("view", frame);
            auto key = cv::waitKey(16);
            if (key == 27)
                break;
        }
    }
    if (FLAGS_v)
        cv::destroyAllWindows();
    return 0;
}
